/*
 * 代号：凤凰
 * http://www.jphenix.org
 * 2014-06-04
 * V4.0
 */
package com.jphenix.driver.log.xlogc;

import com.jphenix.driver.log.util.LogAlertCode;
import com.jphenix.driver.threadpool.ThreadSession;
import com.jphenix.kernel.baseobject.instanceb.ABase;
import com.jphenix.share.lang.SBoolean;
import com.jphenix.standard.docs.ClassInfo;
import com.jphenix.standard.log.ILogShadow;

import java.io.OutputStream;
import java.io.PrintStream;

/**
 * 错入日志输出流
 * 
 * 2018-07-31 设置故障码，细化成前台错误和后台错误
 * 2019-01-31 增加了判断是否不输出日志
 * 2019-02-01 修改了是否输出错误日志线程参数主键
 * 2019-05-16 halt后，有些连接的Tcp Socket 会出现TIME_WAIT 和 CLOSE_WAIT，所以遇到这种情况时，在配置文件中增加system_no_halt参数
 * 2020-03-27 在执行终止系统之前，先输出一条日志。有时候执行终止时，卡在那里
 * 2020-05-07 不该在这个类中执行 System.err.print方法
 * 
 * @author 刘虻
 * 2011-12-27 下午1:26:45
 */
@ClassInfo({"2020-05-07 18:00","错入日志输出流"})
public class ErrorFilterStream extends PrintStream {
	
	protected ILogShadow logShadow = null;	//日志影子类
	protected OutputStream os = null; //输出流
	protected boolean
						showLog		= false		//是否输出日志
						,writeLog	= false;	//是否写入日志
	
	/**
	 * 构造函数
	 * @author 刘虻
	 * @param out
	 */
	public ErrorFilterStream(
			OutputStream out
			,XLogFilter logShadow
			,boolean showLog
			,boolean writeLog) {
		super(out,true);
		os = out;
		this.logShadow = logShadow;
		this.showLog = showLog;
		this.writeLog = writeLog;
	}
	
	
	/**
	 * 覆盖方法
	 */
	@Override
    public void print(String s) {
		if(SBoolean.valueOf(ThreadSession.get("_nolog_"))) {
			return;
		}
        if(showLog) {
            try {
                os.write(s.getBytes());
            }catch(Exception e) {}
        }
        //设置故障码
        if(ThreadSession.containsKey("_action_")) {
        	logShadow.setAlertCode(LogAlertCode.NORMAL_ERROR_FRONT);
        }else {
        	logShadow.setAlertCode(LogAlertCode.NORMAL_ERROR_BACK);
        }
        logShadow.writeLogEvent(s);
        if(writeLog) {
            logShadow.write(s.getBytes());
        }
        if(s.indexOf("OutOfMemoryError")>-1 
                || s.indexOf("Too many open files")>-1) {
        	logShadow.write(("\n\n11-----------------------------------------------------------------------\n"
        			+"The Log Found OutOfMemoryError Or Too many open files Exception Server Has Stoped\n"
        		    +"--------------------------------------------------------------------------------------\n").getBytes());
    	    //注意：halt后，有些连接的Tcp Socket 会出现TIME_WAIT 和 CLOSE_WAIT
    	    //，所以遇到这种情况时，在配置文件中增加<system_no_halt>true</system_no_halt>
            if(logShadow!=null && logShadow instanceof ABase && SBoolean.valueOf(((ABase)logShadow).p("system_no_halt"))) {
            	logShadow.write("******System Begin Exit******".getBytes());
            	System.exit(1);
            }else {
            	logShadow.write("******System Begin Halt******".getBytes());
            	Runtime.getRuntime().halt(1);
            }
        }
    }
	
	/**
	 * 覆盖方法
	 * 刘虻
	 * 2010-8-24 上午11:14:44
	 */
	@Override
    public void write(byte[] buf, int off, int len) {
		if(SBoolean.valueOf(ThreadSession.get("_nolog_"))) {
			return;
		}
		if(showLog) {
			try {
				os.write(buf,off,len);
			}catch(Exception e) {}
		}
        //设置故障码
        if(ThreadSession.containsKey("_action_")) {
        	logShadow.setAlertCode(LogAlertCode.NORMAL_ERROR_FRONT);
        }else {
        	logShadow.setAlertCode(LogAlertCode.NORMAL_ERROR_BACK);
        }
		logShadow.writeLogEvent(new String(buf,off,len));
		if(writeLog) {
			logShadow.write(buf,off,len);
		}
	}


	/**
	 * 覆盖方法
	 * 刘虻
	 * 2010-8-24 上午11:15:04
	 */
	@Override
    public void write(byte[] b) {
		if(SBoolean.valueOf(ThreadSession.get("_nolog_"))) {
			return;
		}
		if(showLog) {
			try {
				os.write(b);
			}catch(Exception e) {}
		}
        //设置故障码
        if(ThreadSession.containsKey("_action_")) {
        	logShadow.setAlertCode(LogAlertCode.NORMAL_ERROR_FRONT);
        }else {
        	logShadow.setAlertCode(LogAlertCode.NORMAL_ERROR_BACK);
        }
		logShadow.writeLogEvent(new String(b));
		if(writeLog) {
			logShadow.write(b);
		}
	}
}
